using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace DimensionsHelper.Client.Controls;


[TemplatePart(Name = ColorPanelTemplateName, Type = typeof(Panel))]
[TemplatePart(Name = PickerTemplateName, Type = typeof(Thumb))]
[TemplatePart(Name = HueColorSliderTemplateName, Type = typeof(Slider))]
[TemplatePart(Name = OpacitySliderTemplateName, Type = typeof(Slider))]
[TemplatePart(Name = UniformGridTemplateName, Type = typeof(UniformGrid))]
public class ColorPanel : Control
{
    
    private const string ColorPanelTemplateName = "PART_ColorPanel";
    private const string PickerTemplateName = "PART_Picker";
    private const string HueColorSliderTemplateName = "PART_HueColorSlider";
    private const string OpacitySliderTemplateName = "PART_OpacitySlider";
    private const string UniformGridTemplateName = "PART_UniformGrid";
    
    public const double ColorPanelWidth = 240;
    public const double ColorPanelHeight = 120;

    private bool IsDragging => _thumb is { IsDragging: true };

    
    [Flags]
    private enum UpdateFlags
    {
        None = 0,
        H = 0x1,
        S = 0x2,
        V = 0x4,
        A = 0x8,
        R = 0x10,
        G = 0x20,
        B = 0x40,
        Hue = 0x80,
        Picker = 0x100,
        SelectedColorText = 0x200,
        SelectedColor = 0x400,
        SelectedDrawingColor = 0x800,
        SelectedBrush = 0x1000,
        SelectedRgbBrush = 0x2000,

        Opacity = 0x4000,

        Argb = A | R | G | B,
        Hsv = H | S | V
    }
    
    private Panel? _colorPanel;
    private Slider? _hueSlider;
    private bool _isLoaded;
    private Slider? _opacitySlider;

    
    // 当更新颜色相关的属性值时，往往需要同时更新其他的关联属性。
    // 在更新各个属性时，都需要调用 UpdateColor 方法。
    // 为了防止递归调用，使用此字段标记当前正在更新的属性。
    private UpdateFlags _preventUpdatingFlags = UpdateFlags.None;
    private Thumb? _thumb;

    // 此字段记录开始更新的属性二进制位。使用此字段标记需要更新的属性，
    // 每次更新一个属性值，将指定的二进制位从此字段值中移除。当此字段
    // 值变为 UpdateFlags.None 时，表示更新过程已完成。
    private UpdateFlags _updatingFlags = UpdateFlags.None;


    private void SetValueInternal(DependencyProperty property, object? value, UpdateFlags flags)
    {
        if (IsUpdatePrevented(flags))
        {
            return;
        }

        _preventUpdatingFlags |= flags;
        SetValue(property, value);
        _preventUpdatingFlags &= ~flags;
        _updatingFlags &= ~flags;
    }
    

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _hueSlider = GetTemplateChild(HueColorSliderTemplateName) as Slider;
        _opacitySlider = GetTemplateChild(OpacitySliderTemplateName) as Slider;
        _colorPanel = GetTemplateChild(ColorPanelTemplateName) as Panel;
        _thumb = GetTemplateChild(PickerTemplateName) as Thumb;

        if (GetTemplateChild(UniformGridTemplateName) is UniformGrid uniformGrid)
        {
            InitUniformGrid(uniformGrid);
        }

        if (_hueSlider != null)
        {
            _hueSlider.ValueChanged += HueSlider_ValueChanged;
        }

        if (_opacitySlider != null)
        {
            _opacitySlider.ValueChanged += OpacitySlider_ValueChanged;
        }

        if (_thumb != null)
        {
            _thumb.DragDelta += Thumb_DragDelta;
        }

        if (_colorPanel != null)
        {
            _colorPanel.MouseLeftButtonDown += ColorPanel_MouseLeftButtonDown;
        }
        
        if (_isLoaded)
        {
            return;
        }

        UpdateColor(SelectedColor);
        _isLoaded = true;
    }

    
    private HsvColor GetHsv()
    {
        return new HsvColor(H, S, V);
    }
    

    private void ColorPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (_colorPanel == null || _thumb == null || !_colorPanel.IsMouseOver)
        {
            return;
        }

        Point pos = Mouse.GetPosition(_colorPanel);
        Canvas.SetLeft(_thumb, pos.X);
        Canvas.SetTop(_thumb, pos.Y);
        PickColor(pos.X, pos.Y);
    }


    private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
    {
        if (sender is not Thumb thumb)
        {
            return;
        }

        double x = Canvas.GetLeft(thumb);
        double y = Canvas.GetTop(thumb);

        x = double.IsNaN(x) ? 0 : x;
        y = double.IsNaN(y) ? 0 : y;

        x += e.HorizontalChange;
        y += e.VerticalChange;

        if (x < 0)
        {
            x = 0;
        }

        if (y < 0)
        {
            y = 0;
        }

        if (_colorPanel != null)
        {
            if (x > _colorPanel.ActualWidth)
            {
                x = _colorPanel.ActualWidth;
            }

            if (y > _colorPanel.ActualHeight)
            {
                y = _colorPanel.ActualHeight;
            }
        }

        Canvas.SetLeft(thumb, x);
        Canvas.SetTop(thumb, y);

        PickColor(x, y);
    }


    // 拖动明度条时，应当同时更新选中的颜色
    private void OpacitySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        byte opacity = (byte)e.NewValue;
        Color color = SelectedColor;
        UpdateColor(Color.FromArgb(opacity, color.R, color.G, color.B),
            ~(UpdateFlags.R | UpdateFlags.G | UpdateFlags.B | UpdateFlags.Hue | UpdateFlags.Opacity),
            useSpecifiedFlagsAsUpdateFlags: true);
    }

    
    private void UpdateOpacitySliderValueInternal(double opacity)
    {
        if (_opacitySlider == null)
        {
            return;
        }

        _opacitySlider.ValueChanged -= OpacitySlider_ValueChanged;
        _opacitySlider.Value = opacity;
        _opacitySlider.ValueChanged += OpacitySlider_ValueChanged;
    }


    /// <summary>
    ///     判断指定的二进制位是否全部被阻止了。
    /// </summary>
    private bool IsUpdatePrevented(UpdateFlags flags)
    {
        return (_preventUpdatingFlags & flags) == flags;
    }



    private static bool TryConvertToColor(string text, out Color color)
    {
        color = default;

        try
        {
            color = (Color)ColorConverter.ConvertFromString(text);
            return true;
        }
        catch
        {
            // ignored
        }

        return false;
    }


    private void OnDefaultColorButtonClick(object sender, RoutedEventArgs e)
    {
        Button button = (Button)sender;
        UpdateColor(((SolidColorBrush)button.Background).Color);
    }



    private Button CreateDefaultColorButton(int row, int col, string background)
    {
        Button button = new();

        Grid.SetRow(button, row);
        Grid.SetColumn(button, col);

        if (TryConvertToColor(background, out Color color))
        {
            button.Background = new SolidColorBrush(color);
        }

        button.Click += OnDefaultColorButtonClick;

        return button;
    }


    private void InitUniformGrid(UniformGrid grid)
    {
        int rows = grid.Rows;
        int cols = grid.Columns;

        int index = 0;

        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                if (index >= ColorHelper.DefaultColorList.Length)
                {
                    break;
                }

                grid.Children.Add(CreateDefaultColorButton(i, j, ColorHelper.DefaultColorList[index]));
                index++;
            }
        }
    }


    private void PickColor(double left, double top, UpdateFlags preventFlags = UpdateFlags.None)
    {
        if (_colorPanel == null || _colorPanel.Height == 0 || _colorPanel.Width == 0)
        {
            return;
        }

        //
        // (255,255,255)      (255,0,0)  右上角是色相颜色
        //   +----------------+
        //   |     |          |
        //   |     y          |
        //   |     |          |
        //   |--x--+          |
        //   |    1-y         |
        //   +----------------+
        // (0,0,0)           (0,0,0)
        // 
        // 取色板的白色和黑色渐变都只覆盖半个面板的面积。

        double x = left / ColorPanelWidth;
        double y = 1 - (top / ColorPanelHeight);
        Color hueColor = HueBrush.Color;

        Color leftMid = Color.FromRgb((byte)(255 * y), (byte)(255 * y), (byte)(255 * y));
        Color rightMid = Color.FromRgb((byte)(hueColor.R * y), (byte)(hueColor.G * y), (byte)(hueColor.B * y));

        int subR = leftMid.R - rightMid.R;
        int subG = leftMid.G - rightMid.G;
        int subB = leftMid.B - rightMid.B;

        Color color = Color.FromArgb(A,
            (byte)(leftMid.R - (subR * x)),
            (byte)(leftMid.G - (subG * x)),
            (byte)(leftMid.B - (subB * x)));

        UpdateColor(color, ~(UpdateFlags.Picker | UpdateFlags.Hue | preventFlags),
            useSpecifiedFlagsAsUpdateFlags: true);
    }


    private (double X, double Y) ComputePanelPositionOfColor(Color color)
    {
        if (_colorPanel == null)
        {
            return (0, 0);
        }

        byte min = Math.Min(color.R, Math.Min(color.G, color.B));
        byte max = Math.Max(color.R, Math.Max(color.G, color.B));

        double left = max == 0 ? 0 : (1 - (min / (double)max)) * ColorPanelWidth;
        double top = (1 - (max / 255.0)) * ColorPanelHeight;

        return (left, top);
    }


    private void PickColor(UpdateFlags preventFlags)
    {
        if (_colorPanel == null || _thumb == null)
        {
            return;
        }

        double top = Math.Min(ColorPanelHeight, Canvas.GetTop(_thumb));
        double left = Math.Min(ColorPanelWidth, Canvas.GetLeft(_thumb));

        PickColor(left, top, preventFlags);
    }


    private void UpdatePickerPosition(Color color)
    {
        if (_thumb == null || IsDragging || IsUpdatePrevented(UpdateFlags.Picker))
        {
            return;
        }

        (double x, double y) = ComputePanelPositionOfColor(color);
        Canvas.SetLeft(_thumb, x);
        Canvas.SetTop(_thumb, y);
    }

    

    private void HueSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        Color color;

        // 起始位置
        if (e.NewValue == 0)
        {
            color = ColorHelper.ColorBounds[0];
        }
        // 结束位置
        else if ((int)e.NewValue == ColorHelper.ColorBounds.Length - 1)
        {
            color = ColorHelper.ColorBounds[^1];
        }
        else
        {
            int lowerIndex = (int)e.NewValue;
            Color lower = ColorHelper.ColorBounds[lowerIndex];
            Color upper = ColorHelper.ColorBounds[lowerIndex + 1];
            double sub = e.NewValue - lowerIndex;

            byte a = (byte)(lower.A - ((lower.A - upper.A) * sub));
            byte r = (byte)(lower.R - ((lower.R - upper.R) * sub));
            byte g = (byte)(lower.G - ((lower.G - upper.G) * sub));
            byte b = (byte)(lower.B - ((lower.B - upper.B) * sub));

            color = Color.FromArgb(a, r, g, b);
        }

        HueBrush = new SolidColorBrush(color);
        // 色相变化后，在取色板上更新颜色
        PickColor(UpdateFlags.Hue);
    }


    private void UpdateHueSliderValueInternal(double hue)
    {
        if (_hueSlider == null)
        {
            return;
        }

        _hueSlider.ValueChanged -= HueSlider_ValueChanged;
        _hueSlider.Value = hue;
        _hueSlider.ValueChanged += HueSlider_ValueChanged;
    }


    /// <summary>
    ///     更新颜色时主要使用的方法。在更新颜色时，需要同时更新多个属性：
    ///     SelectedColor, SelectedColorText, SelectedDrawingColor, SelectedBrush, SelectedRgbBrush。
    ///     这些依赖属性在更新值时还会触发回调，回调也可能会调用此方法，由此构成递归调用。
    /// </summary>
    private void UpdateColor(Color color, UpdateFlags specifiedFlags = UpdateFlags.None, HsvColor? hsv = null,
        bool useSpecifiedFlagsAsUpdateFlags = false)
    {
        // 如果 useSpecifiedFlagsAsUpdateFlags 为 true，对 specifiedFlags 取反并赋值给 _preventUpdatingFlags
        if (useSpecifiedFlagsAsUpdateFlags)
        {
            _preventUpdatingFlags = ~specifiedFlags;
            _updatingFlags = specifiedFlags;
        }
        else if (_updatingFlags <= UpdateFlags.None)
        {
            _preventUpdatingFlags = UpdateFlags.None;
            _updatingFlags = ~UpdateFlags.None;
        }

        // 如果指定属性正在更新或被阻止更新，阻止递归调用
        if (specifiedFlags > UpdateFlags.None && IsUpdatePrevented(specifiedFlags))
        {
            return;
        }

        // 更新颜色相关属性。
        SelectedColor = color;
        SelectedColorText = ColorHelper.ToHexName(color);
        SelectedRgbBrush = new SolidColorBrush(Color.FromRgb(color.R, color.G, color.B));
        SelectedBrush = new SolidColorBrush(color);
        SelectedDrawingColor = System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B);

        // A R G B
        if (!IsUpdatePrevented(UpdateFlags.Argb))
        {
            A = color.A;
            R = color.R;
            G = color.G;
            B = color.B;
        }

        // Opacity Value
        if (!IsUpdatePrevented(UpdateFlags.Opacity))
        {
            UpdateOpacitySliderValueInternal(color.A);
        }

        // HSV
        if (!IsUpdatePrevented(UpdateFlags.Hsv | UpdateFlags.Hue))
        {
            hsv ??= HsvColor.FromRgb(color.R, color.G, color.B);

            if (!IsUpdatePrevented(UpdateFlags.Hue))
            {
                // 转换为色相条的索引
                // 色相条起始是0，结尾是360，色相条包含12种颜色，并且hue值是0-1的百分比值，
                // 因此，此处是 hue * 360 / 30 => hue * 12
                int hueIndex = (int)Math.Round(hsv.H * 12, 0);
                UpdateHueSliderValueInternal(hueIndex);
                HueBrush = new SolidColorBrush(ColorHelper.ColorBounds[hueIndex]);
            }

            // 更新HSV
            H = hsv.H;
            S = hsv.S;
            V = hsv.V;
        }

        // picker
        UpdatePickerPosition(color);

        // 结束更新，当 _updatingFlags == UpdateFlags.None 时，表示无属性需要继续更新，将 _preventFlags 设置为 None.
        if (_updatingFlags > UpdateFlags.None)
        {
            return;
        }

        _updatingFlags = UpdateFlags.None;
        _preventUpdatingFlags = UpdateFlags.None;
    }



    #region Properties


    public static readonly DependencyProperty CornerRadiusProperty =
        Border.CornerRadiusProperty.AddOwner(typeof(ColorPanel));

    
    public static readonly DependencyProperty HueBrushProperty =
        DependencyProperty.Register(
            nameof(HueBrush),
            typeof(SolidColorBrush),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                new SolidColorBrush(ColorHelper.ColorBounds[3]),
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnHueBrushPropertyChanged));


    /// <summary>
    ///     当前的色相颜色。
    /// </summary>
    public SolidColorBrush HueBrush
    {
        get => (SolidColorBrush)GetValue(HueBrushProperty);
        set => SetValueInternal(HueBrushProperty, value, UpdateFlags.Hue);
    }


    private static void OnHueBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        if (panel.IsUpdatePrevented(UpdateFlags.Hue))
        {
            return;
        }

        panel.PickColor(UpdateFlags.Hue);
    }



    public static readonly DependencyProperty SelectedBrushProperty =
        DependencyProperty.Register(
            nameof(SelectedBrush),
            typeof(Brush),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Brushes.White,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSelectedBrushPropertyChanged,
                CoerceSelectedBrush));


    /// <summary>
    ///     ARGB颜色笔刷，包含Alpha值
    /// </summary>
    public Brush SelectedBrush
    {
        get => (Brush)GetValue(SelectedBrushProperty);
        set => SetValueInternal(SelectedBrushProperty, value, UpdateFlags.SelectedBrush);
    }


    private static void OnSelectedBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        if (panel.IsUpdatePrevented(UpdateFlags.SelectedBrush))
        {
            return;
        }

        SolidColorBrush? brush = (SolidColorBrush)e.NewValue;
        panel.UpdateColor(brush.Color, UpdateFlags.SelectedBrush);
    }


    private static object CoerceSelectedBrush(DependencyObject d, object baseValue)
    {
        return baseValue is SolidColorBrush ? baseValue : Brushes.White;
    }


    public static readonly DependencyProperty SelectedRgbBrushProperty =
        DependencyProperty.Register(
            nameof(SelectedRgbBrush),
            typeof(Brush),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Brushes.White,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSelectedRgbBrushPropertyChanged));


    /// <summary>
    ///     不带有Alpha值的颜色笔刷
    /// </summary>
    public Brush SelectedRgbBrush
    {
        get => (Brush)GetValue(SelectedRgbBrushProperty);
        set => SetValueInternal(SelectedRgbBrushProperty, value, UpdateFlags.SelectedRgbBrush);
    }


    private static void OnSelectedRgbBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        if (e.NewValue is not SolidColorBrush rgbBrush || panel.IsUpdatePrevented(UpdateFlags.SelectedRgbBrush))
        {
            return;
        }

        panel.UpdateColor(rgbBrush.Color, UpdateFlags.SelectedRgbBrush);
    }


    public static readonly DependencyProperty SelectedColorProperty =
        DependencyProperty.Register(
            nameof(SelectedColor),
            typeof(Color),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Colors.White,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSelectedColorPropertyChanged));


    /// <summary>
    ///     当前选中的ARGB颜色
    /// </summary>
    public Color SelectedColor
    {
        get => (Color)GetValue(SelectedColorProperty);
        set => SetValueInternal(SelectedColorProperty, value, UpdateFlags.SelectedColor);
    }


    private static void OnSelectedColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        if (panel.IsUpdatePrevented(UpdateFlags.SelectedColor))
        {
            return;
        }

        panel.UpdateColor((Color)e.NewValue, UpdateFlags.SelectedColor);
    }


    public static readonly DependencyProperty SelectedDrawingColorProperty =
        DependencyProperty.Register(
            nameof(SelectedDrawingColor),
            typeof(System.Drawing.Color),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                System.Drawing.Color.White,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSelectedDrawingColorPropertyChanged));


    /// <summary>
    ///     当前选取的<see cref="System.Drawing.Color" />类型的颜色。
    /// </summary>
    public System.Drawing.Color SelectedDrawingColor
    {
        get => (System.Drawing.Color)GetValue(SelectedDrawingColorProperty);
        set => SetValueInternal(SelectedDrawingColorProperty, value, UpdateFlags.SelectedDrawingColor);
    }


    private static void OnSelectedDrawingColorPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        if (panel.IsUpdatePrevented(UpdateFlags.SelectedDrawingColor))
        {
            return;
        }

        System.Drawing.Color drawingColor = (System.Drawing.Color)e.NewValue;
        panel.UpdateColor(Color.FromArgb(drawingColor.A, drawingColor.R, drawingColor.G, drawingColor.B),
            UpdateFlags.SelectedDrawingColor);
    }


    public static readonly DependencyProperty SelectedColorTextProperty =
        DependencyProperty.Register(
            nameof(SelectedColorText),
            typeof(string),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                ColorHelper.ToHexName(Colors.White),
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnSelectedColorTextPropertyChanged));


    /// <summary>
    ///     当前选取的颜色文本名，格式为#{A:FF}{R:FF}{G:FF}{B:FF}
    /// </summary>
    public string? SelectedColorText
    {
        get => (string?)GetValue(SelectedColorTextProperty);
        set => SetValueInternal(SelectedColorTextProperty, value, UpdateFlags.SelectedColorText);
    }


    private static void OnSelectedColorTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;
        string? newText = (string)e.NewValue;

        if (panel.IsUpdatePrevented(UpdateFlags.SelectedColorText) || !TryConvertToColor(newText, out Color color))
        {
            return;
        }

        panel.UpdateColor(color, UpdateFlags.SelectedColorText);
    }


    public static readonly DependencyProperty AProperty =
        DependencyProperty.Register(
            nameof(A),
            typeof(byte),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Colors.White.A,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnARGBPropertyChanged));


    /// <summary>
    ///     透明通道值, 0-255
    /// </summary>
    public byte A
    {
        get => (byte)GetValue(AProperty);
        set => SetValueInternal(AProperty, value, UpdateFlags.A);
    }


    public static readonly DependencyProperty RProperty =
        DependencyProperty.Register(
            nameof(R),
            typeof(byte),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Colors.White.R,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnARGBPropertyChanged));


    /// <summary>
    ///     红色值, 0-255
    /// </summary>
    public byte R
    {
        get => (byte)GetValue(RProperty);
        set => SetValueInternal(RProperty, value, UpdateFlags.R);
    }


    public static readonly DependencyProperty GProperty =
        DependencyProperty.Register(
            nameof(G),
            typeof(byte),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Colors.White.G,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnARGBPropertyChanged));


    /// <summary>
    ///     绿色值, 0-255
    /// </summary>
    public byte G
    {
        get => (byte)GetValue(GProperty);
        set => SetValueInternal(GProperty, value, UpdateFlags.G);
    }


    public static readonly DependencyProperty BProperty =
        DependencyProperty.Register(
            nameof(B),
            typeof(byte),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                Colors.White.B,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnARGBPropertyChanged));


    /// <summary>
    ///     蓝色值, 0-255
    /// </summary>
    public byte B
    {
        get => (byte)GetValue(BProperty);
        set => SetValueInternal(BProperty, value, UpdateFlags.B);
    }


    private static void OnARGBPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        UpdateFlags updateFlags = e.Property.Name switch
        {
            nameof(A) => UpdateFlags.A,
            nameof(R) => UpdateFlags.R,
            nameof(G) => UpdateFlags.G,
            nameof(B) => UpdateFlags.B,
            _ => UpdateFlags.None
        };

        if (panel.IsUpdatePrevented(updateFlags))
        {
            return;
        }

        panel.UpdateColor(Color.FromArgb(panel.A, panel.R, panel.G, panel.B), updateFlags);
    }


    public static readonly DependencyProperty HProperty =
        DependencyProperty.Register(
            nameof(H),
            typeof(double),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                0d,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnHSVPropertyChanged));


    /// <summary>
    ///     色相值，0.0~1.0
    /// </summary>
    public double H
    {
        get => (double)GetValue(HProperty);
        set => SetValueInternal(HProperty, value, UpdateFlags.H);
    }


    public static readonly DependencyProperty SProperty =
        DependencyProperty.Register(
            nameof(S),
            typeof(double),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                0d,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnHSVPropertyChanged));


    /// <summary>
    ///     饱和度值 0~1.0
    /// </summary>
    public double S
    {
        get => (double)GetValue(SProperty);
        set => SetValueInternal(SProperty, value, UpdateFlags.S);
    }


    public static readonly DependencyProperty VProperty =
        DependencyProperty.Register(
            nameof(V),
            typeof(double),
            typeof(ColorPanel),
            new FrameworkPropertyMetadata(
                0d,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnHSVPropertyChanged));

    /// <summary>
    ///     亮度值，0.0~1.0
    /// </summary>
    public double V
    {
        get => (double)GetValue(VProperty);
        set => SetValueInternal(VProperty, value, UpdateFlags.V);
    }


    private static void OnHSVPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ColorPanel panel = (ColorPanel)d;

        if (panel.IsDragging)
        {
            return;
        }

        UpdateFlags updateFlags = e.Property.Name switch
        {
            nameof(H) => UpdateFlags.H,
            nameof(S) => UpdateFlags.S,
            nameof(V) => UpdateFlags.V,
            _ => UpdateFlags.None
        };

        if (panel.IsUpdatePrevented(updateFlags))
        {
            return;
        }

        // 当HSV的属性发生变化时，应当更新ARGB值，同时需要更新HSV颜色
        HsvColor hsv = panel.GetHsv();
        Color color = hsv.ToArgb(panel.A);
        panel.UpdateColor(color, updateFlags, hsv);
    }


    #endregion
    
}